/**
 * 日志告警服务
 * 作者：GodMainCode
 * 创建时间：2024-01-17
 * 修改时间：2024-01-17
 * 修改人：GodMainCode
 */

import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, MoreThanOrEqual } from 'typeorm';
import { Cron, CronExpression } from '@nestjs/schedule';
import { Log } from './entities/log.entity';
import { LogAlertConfigDto } from './dto/log-alert-config.dto';
import axios from 'axios';

@Injectable()
export class LogAlertService {
  private readonly logger = new Logger(LogAlertService.name);
  private alertConfigs: LogAlertConfigDto[] = [];

  constructor(
    @InjectRepository(Log)
    private readonly logRepository: Repository<Log>,
  ) {}

  /**
   * 添加告警配置
   * @param config 告警配置
   */
  addAlertConfig(config: LogAlertConfigDto): void {
    this.alertConfigs.push(config);
  }

  /**
   * 每分钟检查告警条件
   */
  @Cron(CronExpression.EVERY_MINUTE)
  async checkAlerts() {
    for (const config of this.alertConfigs) {
      try {
        const count = await this.checkAlertCondition(config);
        if (count >= config.threshold) {
          await this.sendAlert(config, count);
        }
      } catch (error) {
        this.logger.error(`检查告警失败: ${error.message}`);
      }
    }
  }

  /**
   * 检查告警条件
   * @param config 告警配置
   * @returns Promise<number> 符合条件的日志数量
   */
  private async checkAlertCondition(config: LogAlertConfigDto): Promise<number> {
    const timeWindow = new Date();
    timeWindow.setMinutes(timeWindow.getMinutes() - config.timeWindow);

    return await this.logRepository.count({
      where: {
        type: config.type,
        level: config.level,
        created_at: MoreThanOrEqual(timeWindow),
      },
    });
  }

  /**
   * 发送告警
   * @param config 告警配置
   * @param count 触发告警的日志数量
   */
  private async sendAlert(config: LogAlertConfigDto, count: number): Promise<void> {
    const alertMessage = {
      name: config.name,
      type: config.type,
      level: config.level,
      count,
      timeWindow: config.timeWindow,
      timestamp: new Date().toISOString(),
    };

    for (const channel of config.notifyChannels) {
      try {
        switch (channel) {
          case 'webhook':
            if (config.webhookUrl) {
              await this.sendWebhookAlert(config.webhookUrl, alertMessage);
            }
            break;
          case 'email':
            if (config.receivers?.length) {
              await this.sendEmailAlert(config.receivers, alertMessage);
            }
            break;
          default:
            this.logger.warn(`不支持的告警通知方式: ${channel}`);
        }
      } catch (error) {
        this.logger.error(`发送告警失败 (${channel}): ${error.message}`);
      }
    }
  }

  /**
   * 发送Webhook告警
   * @param url Webhook地址
   * @param message 告警消息
   */
  private async sendWebhookAlert(url: string, message: any): Promise<void> {
    await axios.post(url, message);
  }

  /**
   * 发送邮件告警
   * @param receivers 接收者列表
   * @param message 告警消息
   */
  private async sendEmailAlert(receivers: string[], message: any): Promise<void> {
    // TODO: 实现邮件发送逻辑
    this.logger.log(`模拟发送邮件到 ${receivers.join(', ')}`);
  }

  /**
   * 获取所有告警配置
   * @returns LogAlertConfigDto[] 告警配置列表
   */
  getAlertConfigs(): LogAlertConfigDto[] {
    return this.alertConfigs;
  }

  /**
   * 删除告警配置
   * @param name 告警配置名称
   */
  removeAlertConfig(name: string): void {
    this.alertConfigs = this.alertConfigs.filter(config => config.name !== name);
  }

  /**
   * 测试告警配置
   * @param config 告警配置
   */
  async testAlert(config: LogAlertConfigDto): Promise<void> {
    const alertMessage = {
      name: config.name,
      type: config.type,
      level: config.level,
      count: 1,
      timeWindow: config.timeWindow,
      timestamp: new Date().toISOString(),
      isTest: true,
    };

    for (const channel of config.notifyChannels) {
      try {
        switch (channel) {
          case 'webhook':
            if (config.webhookUrl) {
              await this.sendWebhookAlert(config.webhookUrl, alertMessage);
            }
            break;
          case 'email':
            if (config.receivers?.length) {
              await this.sendEmailAlert(config.receivers, alertMessage);
            }
            break;
          default:
            this.logger.warn(`不支持的告警通知方式: ${channel}`);
        }
      } catch (error) {
        this.logger.error(`测试告警失败 (${channel}): ${error.message}`);
        throw error;
      }
    }
  }
} 